#include "glWindow.hpp"

#define USE_3D_MODEL 1

#ifndef USE_3D_MODEL
float vertices[] = {
    // 位置                 // 纹理坐标
    -0.5f, -0.5f, 0.0f,     0.0f, 0.0f,
    0.5f,  -0.5f, 0.0f,     1.0f, 0.0f,
    0.0f,  0.5f,  0.0f,     0.5f, 1.0f
};
#else
// OpenGL还没有初始化, 如果直接在此处初始化方块, 会导致Error
CubeMesh *cube = nullptr;

#endif


AUVOpenGLWidget::AUVOpenGLWidget( QWidget *parent ) 
: QOpenGLWidget( parent ), 
_camera(QVector3D( 0.0f, 0.0f, 3.0f )),
_firstMouse( true ),
_mousePressed( false ),
_cameraSpeed( 2.5f ),
_mouseSensitivity( 0.1f )
{
    setFocusPolicy( Qt::StrongFocus );
    _timer = new QTimer(this);
    connect( _timer, &QTimer::timeout, this, &AUVOpenGLWidget::updateAnimation );
    _timer->start( 16 );        // 60FPS
}

// ----------------- 初始化 -----------------
void AUVOpenGLWidget::initializeGL() {
    initializeOpenGLFunctions();

#ifdef USE_3D_MODEL
    cube = new CubeMesh();
    cube->init();

#else
    // 1. 创建一个菜谱编号 和 仓库编号
    glGenVertexArrays( 1, &_VAO );
    glGenBuffers( 1, &_VBO );

    // 2. 使用这个菜谱 调用指定仓库
    glBindVertexArray( _VAO );
    glBindBuffer( GL_ARRAY_BUFFER, _VBO );

    // 3. 从仓库取食材
    glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW );

    // 4. 规划食材怎么做
    // --顶点属性1
    //                     | 顶点属性索引值为0 用于glEnableVertexAttribArray(0);
    //                     V
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0 );
    glEnableVertexAttribArray(0);
    // --顶点属性2
    //                        | 该顶点属性大小为2 包含两个分量( x, y );
    //                        V
    glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)( 3*sizeof( float ) ) );
    glEnableVertexAttribArray(1);
#endif

    // :/QtWidgetInOpenGL/shader/triangle.vert.glsl  Widgets开发用的是 : 开头的qrc路径
    _shaderProgram = createShaderProgram( ":/QtWidgetInOpenGL/shader/triangle.vert.glsl", ":/QtWidgetInOpenGL/shader/triangle.frag.glsl");

    // 获取 uniform 在shaderProgram 中的位置
    _timeLocation           = glGetUniformLocation( _shaderProgram, "time" );
    _transformLocation      = glGetUniformLocation( _shaderProgram, "transform" );
    _alphaLocation          = glGetUniformLocation( _shaderProgram, "alpha" );
    _tintColorLocation      = glGetUniformLocation( _shaderProgram, "tintColor" );
    _viewLocation           = glGetUniformLocation( _shaderProgram, "view" );
    _projectionLocation     = glGetUniformLocation( _shaderProgram, "projection" );

    // 加载纹理 使用静态函数
    _textureID = TextureUtil::loadTexture( ":/assets/webPageTexture.png", this );

    glEnable( GL_DEPTH_TEST );  // 深度测试
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

// ----------------- 绘图循环 -----------------
void AUVOpenGLWidget::paintGL() {
    glClearColor( 0.1f, 0.1f, 0.1f, 0.5f );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );   // 添加深度缓冲清理

    // 使用着色器
    glUseProgram( _shaderProgram );
    // 传递 uniform 值
    float time = QTime::currentTime().msecsSinceStartOfDay() / 1000.0f;
    glUniform1f( _timeLocation, time );

    QMatrix4x4 transform;
    transform.rotate( time * 50, 0, 0, 1 );
    glUniformMatrix4fv( _transformLocation, 1, GL_FALSE, transform.constData() );

    glUniform1f( _alphaLocation, 0.8f );
    glUniform3f( _tintColorLocation, 0.11f, 0.5f, 0.2f );

    // MVP矩阵
    QMatrix4x4 model;
    model.rotate( QTime::currentTime().msecsSinceStartOfDay()/10.0f, 1.0f, 0.3f, 0.5f );
    QMatrix4x4 view = _camera.getViewMatrix();
    QMatrix4x4 projection = _camera.getProjectionMatrix( (float)width()/height() );
    glUniformMatrix4fv( glGetUniformLocation( _shaderProgram, "model" ), 1, GL_FALSE, model.constData() );
    glUniformMatrix4fv( _viewLocation, 1, GL_FALSE, view.constData() );
    glUniformMatrix4fv( _projectionLocation, 1, GL_FALSE, projection.constData() );


    // 绑定纹理
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, _textureID );
    glUniform1i( glGetUniformLocation( _shaderProgram, "ourTexture" ), 0 );

    // 5.做菜(绘制)
#ifndef USE_3D_MODEL
    glBindVertexArray( _VAO );
    glDrawArrays( GL_TRIANGLES, 0 , 3 );
#else
    cube->draw();
#endif

}

// ----------------- 触发重绘 -----------------
void AUVOpenGLWidget::updateAnimation() {
    update();
}


// ----------------- 改变窗口大小回调override -----------------
void AUVOpenGLWidget::resizeGL( int w, int h ) {
    glViewport( 0, 0, w, h );
}

// ----------------- 加载shader -----------------
QString AUVOpenGLWidget::loadShaderSource( const QString& filePath ) {
    QFile file(filePath);
    if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
        qDebug() << "无法打开着色器" << filePath;
        return QString("");
    }

    QTextStream in( &file );
    QString content = in.readAll();
    file.close();

    qDebug() << "open: " << filePath;
    return content;
}

GLuint AUVOpenGLWidget::compileShader( const QString& source, GLenum shaderType ) {
    GLuint shader = glCreateShader( shaderType );

    QByteArray sourceBytes = source.toUtf8();
    const char* sourceCStr = sourceBytes.constData();

    glShaderSource( shader, 1, &sourceCStr, NULL );
    glCompileShader( shader );

    // 检查编译状态
    int success;
    char infoLog[512];
    glGetShaderiv( shader, GL_COMPILE_STATUS, &success );

    if ( !success ) {
        glGetShaderInfoLog( shader, 512, NULL, infoLog );
        QString shaderTypeName = ( shaderType == GL_VERTEX_SHADER ) ? "顶点着色器" : "片段着色器";
        qDebug() << shaderTypeName << "编译失败\n" << infoLog;
        return 0;
    }

    return shader;
}

// ----------------- 创建ShaderProgram -----------------
GLuint AUVOpenGLWidget::createShaderProgram( const QString& vertexPath, const QString& fragPath ) {
    QString vertexSource = loadShaderSource( vertexPath );
    QString fragmentSource = loadShaderSource( fragPath );

    if ( vertexSource.isEmpty() || fragmentSource.isEmpty() ) {
        qDebug() << "着色器源码加载失败";
        return 0;
    }

    GLuint vertexShader = compileShader( vertexSource, GL_VERTEX_SHADER );
    GLuint fragmentShader = compileShader( fragmentSource, GL_FRAGMENT_SHADER );

    // 内嵌字符串方法
    // GLuint vertexShader = compileShader( vertexShaderCode, GL_VERTEX_SHADER );
    // GLuint fragmentShader = compileShader( fragmentShaderCode, GL_FRAGMENT_SHADER );

    if ( vertexShader == 0 || fragmentShader == 0 ) {
        qDebug() << "着色器编译失败";
        return 0;
    } else {
        qDebug() << "vert return: " << vertexShader << "\t" << "frag return: " << fragmentShader;
    }

    GLuint program = glCreateProgram();
    glAttachShader( program, vertexShader );
    glAttachShader( program, fragmentShader );
    glLinkProgram( program );

    // 检查链接状态
    int success;
    char infoLog[512];
    glGetProgramiv(program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(program, 512, NULL, infoLog);
        qDebug() << "着色器程序链接失败:" << infoLog;
        return 0;
    } else {
        // 检查当前状态
        glGetProgramInfoLog( program, 512, NULL, infoLog );
        qDebug() << "After Compile & link Shader Log: " << infoLog;
    }
    
    // 清理着色器对象
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
    qDebug() << "着色器程序创建成功 code: " << program;
    return program;


}

// ----------------- 创建ShaderProgram -----------------
void AUVOpenGLWidget::mousePressEvent( QMouseEvent* event ) {
    if ( event->button() == Qt::LeftButton ) {
        _lastMousePos = event->pos();
        _mousePressed = true;
    }
}
void AUVOpenGLWidget::mouseMoveEvent( QMouseEvent* event ) {
    if ( _mousePressed ) {
        QPoint delta = event->pos() - _lastMousePos;
        _camera.processMouseMovement( delta.x(), -delta.y() );
        _lastMousePos = event->pos();
        update();
    }
}
void AUVOpenGLWidget::wheelEvent( QWheelEvent* event ) {
    _camera.processMouseScroll( event->angleDelta().y() / 120.0f );
    update();
}
void AUVOpenGLWidget::keyPressEvent( QKeyEvent* event ) {
    _camera.processKeyboard( event->key(), 0.016f );    // 16ms间隔
    update();
}